from functools import wraps
from typing import Union

from sqlalchemy.ext.asyncio import AsyncSession

from afast_core.core_plugins.db.sqlalchemy.dependencies_for_fun import get_async_session_maker
# async_scoped_session 是一个可以被用于在异步环境中管理 SQLAlchemy 会话的函数。它可以在不同的异步任务中传递会话，并确保在完成任务时自动提交或回滚会话。
#
# 使用方法如下：
#
#
# 1. 首先，创建一个基于 SQLAlchemy 的异步会话：
#
# async with create_async_session(engine) as session:
#
# 2. 然后，使用 async_scoped_session 来创建可以传入任务中的会话：
#
# scoped_session = async_scoped_session(session)
#
# 3. 使用任务来处理会话：
#
# async with scoped_session() as session:
# 	# do something with the session
#
# 4. 当任务完成时，会话会自动提交或回滚。



import contextlib
from contextvars import ContextVar
from typing import Iterator

from sqlalchemy.ext.asyncio import AsyncSession

from .bind_ import bind_contextvar

from starlette.requests import Request
from starlette.types import ASGIApp, Scope, Receive, Send, Message

AsyncSession_var: ContextVar[AsyncSession] = ContextVar("AsyncSession")
async_session: AsyncSession = bind_contextvar(AsyncSession_var)


class AsyncSessionLoadMiddleware:
    '''
    此类的中间件无法读取响应报文的内容
    '''
    pass

    def __init__(self, app: ASGIApp) -> None:
        self.app = app

    def bind_to_request_state(self, request: Request, **kwargs):
        """
        Takes in a set of kwargs and binds them to gziprequest state
        """
        for key, value in kwargs.items():
            setattr(request.state, key, value)

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        if scope["type"] != "http":
            await self.app(scope, receive, send)
            return
        # 解析当前的请求体
        request = Request(scope, receive=receive)
        # 开启中间件的时候创建对应的会话对象
        # 这里对request.core_app.async_session_maker()非常关键，避免出现回收连接告警提示
        token = AsyncSession_var.set(request.app.async_session_maker())
        try:
            await self.app(scope, receive, send)
        finally:
            # 释放
            AsyncSession_var.reset(token)


class Transactional:
    '''

    '''

    def __call__(self, func):
        '''
        通过装饰器方式来处理异步的任务
        :param func:
        :return:
        '''
        @wraps(func)
        async def _transactional(*args, **kwargs):
            try:
                result = await func(*args, **kwargs)
                #
                await async_session.commit()
            except Exception as e:
                await async_session.rollback()
                raise e
            finally:
                # The garbage collector is trying to clean up connection <AdaptedConnection <aiomysql.connection.Connection object at 0x000001BB37060DC0>>. This feature is unsupported on unsupported on asyncio dbapis that lack a "terminate" feature, since no IO can be performed at this stage to reset the connection. Please close out all connections when they are no longer used, calling ``close()`` or using a context manager to manage their lifetime.
                # sys:1: SAWarning: The garbage collector is trying to clean up connection <AdaptedConnection <aiomysql.connection.Connection object at 0x000001BB37060DC0>>. This feature is unsupported on unsupported on asyncio dbapis that lack a "terminate" feature, since no IO can be performed at this stage to reset the connection. Please close out all connections when they are no longer used, calling ``close()`` or using a context manager to manage their lifetime.
                # 这个错误提示的意思是：垃圾收集器正试图清理连接<AdaptedConnection <aiomysql.connection.Connection object at 0x000001BB37060DC0>>，
                # 但是由于asyncio dbapis缺少“terminate”功能，因此在此阶段无法执行IO以重置连接，因此不支持此功能。请在不再使用连接时关闭所有连接，调用“close()”或使用上下文管理器来管理它们的生命周期。
                # print("结束！！！",id(async_session))
                await async_session.close()
            return result

        return _transactional

